#include "stdafx.h"
#include "Utilities/utilities.h" // if you use STL, please include this line AFTER all other include
#include "Camera.h"
#include "Scene.h"

#define DELTA 1.0f

Camera::Camera() 
	: m_position(0.0f, 0.0f, 0.0f)
	, m_target(0.0f, 0.0f, 0.0f)
	, m_up(0.0f, 1.0f, 0.0f)
	, m_angleV(0.0f)
	//, m_moveFBDistance(0.0f)
	//, m_moveLRDistance(0.0f)
	//, m_rotateUDDegree(0.0f)
	//, m_rotateLRDegree(0.0f)
	//, m_zoomDelta(0.0f)
	, m_zoomLevel(1.0f)
	, m_standardLength(0.0f)
{
}

void Camera::UpdateAllParams()
{
	UpdateAxis();
	UpdateW();
	SetPerspective(m_fovY, m_aspect, m_nearPlane, m_farPlane);
	UpdateVP();
	m_standardLength = (m_position - m_target).Length() * m_zoomLevel;
}

Matrix & Camera::VPMatrix()
{
	return (m_VP);
}

void Camera::SetPerspective(GLfloat fovY, GLfloat aspect, GLfloat nearPlane, GLfloat farPlane)
{
	m_P.SetPerspective(fovY, aspect, nearPlane, farPlane);
}

void Camera::SetPositionTarget(Vector3& pos, Vector3& target)
{
	m_position	= pos;
	m_target	= target;
}

void Camera::Update(float deltaTime )
{
	//m_bHasChanges = false;

	//GLfloat deltaDegree = m_rotateSpeed * deltaTime;
	//GLfloat deltaMove	= m_moveSpeed * deltaTime;
	//GLfloat deltaZoom	= m_zoomSpeed * deltaTime;

	//if (m_bZoomIn && m_zoomLevel < 10.0f) //max zoom = 10x, min zoom = 0.1x
	//	m_zoomDelta += deltaZoom; 
	//if (m_bZoomOut && m_zoomLevel > 0.1f)
	//	m_zoomDelta -= deltaZoom;
	////update the zoom
	//if (m_zoomDelta != 0.0f)
	//{
	//	ZoomInOut();
	//	// No needs to UpdateAxis(); because the zaxis does not change
	//	UpdateW();
	//}

	//if (m_bMoveForward)
	//	m_moveFBDistance -= deltaMove; 
	//if (m_bMoveBackward)
	//	m_moveFBDistance += deltaMove;
	////only update when the move is significant 
	//if (m_moveFBDistance >= DELTA || m_moveFBDistance <= -DELTA) 
	//{
	//	MoveForwardBackward();
	//	// No needs to UpdateAxis(); because the target move along with position
	//	UpdateW();
	//}

	//if (m_bMoveLeft)
	//	m_moveLRDistance -= deltaMove;
	//if (m_bMoveRight)
	//	m_moveLRDistance += deltaMove;
	//if (m_moveLRDistance >= DELTA || m_moveLRDistance <= -DELTA)
	//{
	//	MoveLeftRight();
	//	UpdateW();
	//}

	//if (m_bRotateUp && m_angleV > -0.9f) //prevent the angleV reach 0 or 180 degree
	//	m_rotateUDDegree += deltaDegree;
	//if (m_bRotateDown && m_angleV < 0.9f)
	//	m_rotateUDDegree -= deltaDegree;
	//if (m_rotateUDDegree >= DELTA || m_rotateUDDegree <= -DELTA)
	//{
	//	RotateUpDown();
	//	UpdateAxis();
	//	UpdateW();
	//}

	//if (m_bRotateLeft)
	//	m_rotateLRDegree += deltaDegree;
	//if (m_bRotateRight)
	//	m_rotateLRDegree -= deltaDegree;	
	//if (m_rotateLRDegree >= DELTA || m_rotateLRDegree <= -DELTA)
	//{
	//	RotateLeftRight();
	//	UpdateAxis();
	//	UpdateW();
	//}

	//if (!m_bHasChanges)
	//	return;

	//UpdateVP();
}

void Camera::UpdateAxis()
{
	m_zaxis = ((m_position - m_target)).Normalize();
	m_xaxis = (m_up.Cross(m_zaxis)).Normalize();
	m_yaxis = (m_zaxis.Cross(m_xaxis)).Normalize();
	m_bHasChanges = true;
	//m_angleV = cosin of angle between m_zaxis and m_up , 
	//if near +-1.0 this may cause the cross product between m_zaxis and m_up become 0 and camera 
	//will work unexpectly.
	m_angleV = m_up.Dot(m_zaxis);
}

void Camera::UpdateW()
{
	Matrix R, T;
	T.SetTranslation(m_position.x, m_position.y, m_position.z);
	R.SetRotation(m_xaxis, m_yaxis, m_zaxis);
	m_W = R * T;
	m_bHasChanges = true;
}

void Camera::UpdateVP()
{
	Matrix Ti, Ri;
	Ti.SetTranslation(-m_position.x, -m_position.y, -m_position.z);
	Ri.SetRotationInverse(m_xaxis, m_yaxis, m_zaxis);
	m_V = Ti * Ri;
	m_VP = m_V * m_P;
}

//------------------------------------------
void Camera::MoveForwardBackward()
{
	//m_position += m_zaxis * m_moveFBDistance;
	//m_target += m_zaxis * m_moveFBDistance;
	//m_moveFBDistance = 0.0f;
}

void Camera::MoveLeftRight()
{
	//m_position += m_xaxis * m_moveLRDistance;
	//m_target += m_xaxis * m_moveLRDistance;
	//m_moveLRDistance = 0.0f;
}

//-------------------------------------------
void Camera::RotateLeftRight()
{
	//Vector4 localTarget, localNewTarget, worldNewTarget;
	//Matrix Ry;

	//localTarget = Vector4(0.0f, 0.0f, -(m_position - m_target).Length(), 1.0f);
	//Ry.SetRotationY(m_rotateLRDegree / 180.0f * PI);
	//localNewTarget = localTarget * Ry;
	//worldNewTarget = localNewTarget * m_W;
	//m_target = Vector3(worldNewTarget.x, worldNewTarget.y, worldNewTarget.z);
	//m_rotateLRDegree = 0.0f;
}

void Camera::RotateUpDown()
{
	//Vector4 localTarget, localNewTarget, worldNewTarget;
	//Matrix Rx;

	//localTarget = Vector4(0.0f, 0.0f, -(m_position - m_target).Length(), 1.0f);
	//Rx.SetRotationX(m_rotateUDDegree / 180.0f * PI);
	//localNewTarget = localTarget * Rx;
	//worldNewTarget = localNewTarget * m_W;
	//m_target = Vector3(worldNewTarget.x, worldNewTarget.y, worldNewTarget.z);
	//m_rotateUDDegree = 0.0f;
}

//-------------------------------------------------------------------------
void Camera::ZoomInOut()
{
	//when zoomed, move the position along the zaxis, the target stays the same
	//m_zoomLevel += m_zoomDelta;
	//m_position = m_target + m_zaxis * m_standardLength / m_zoomLevel;
	//m_zoomDelta = 0.0f;
}